// import { Point } from '../ai/ts-geometry-2d/Point';
// import { Line } from '../ai/ts-geometry-2d/Line';
// import { Vector } from '../ai/ts-geometry-2d/Vector';

// enum CollisioObjectType {
//   Unknown = 0,
//   DeskBall = 1,
//   DeskEdge = 2,
//   DeskHole = 3,
// }

// class CollisioObject {
//   public type: CollisioObjectType = CollisioObjectType.DeskBall;
//   public name: string = '';
//   constructor(tp: CollisioObjectType, name: string) {
//     this.type = tp;
//     this.name = name;
//   }
// }

// export class CollisionSphere extends CollisioObject {
//   public position: Point = new Point(0, 0);
//   public velocity: Point = new Point(0, 0);
//   public radius: number = 0.5;
//   constructor(tp: CollisioObjectType, name: string, r: number, x: number, y: number, vx: number, vy: number) {
//     super(tp, name);
//     this.position = new Point(x, y);
//     this.velocity = new Point(vx, vy);
//     this.radius = r;
//   }
//   public clearVelocity() {
//     this.velocity.x = 0;
//     this.velocity.y = 0;
//   }
//   // 判断球是否静止不动
//   public isStatic() {
//     return Math.abs(this.velocity.x) <= 0.05 && Math.abs(this.velocity.y) <= 0.05;
//   }

//   // 计算两个球是否会碰撞，返回碰撞的时间，不会碰撞返回负数
//   public sphereCollision(balla: CollisionSphere) {
//     const dist = (this.position.x - balla.position.x) * (this.position.x - balla.position.x)
//       + (this.position.y - balla.position.y) * (this.position.y - balla.position.y);
//     const dr = (balla.radius + this.radius) * (balla.radius + this.radius);
//     // 已经碰撞在一起
//     if (dist + 0.001 < dr) {
//       return 0;
//     }
//     const ballb = this;
//     const dx = balla.position.x - ballb.position.x;
//     const dy = balla.position.y - ballb.position.y;
//     const vx = balla.velocity.x - ballb.velocity.x;
//     const vy = balla.velocity.y - ballb.velocity.y;

//     const ds = (balla.radius + ballb.radius) * (balla.radius + ballb.radius);
//     const delta = 4 * (dx * vx + dy * vy) * (dx * vx + dy * vy) 
//       - 4 * (vx * vx - vy * vy) * (dx * dx + dy *dy - ds * ds);
    
//     if (delta < 0) {
//       return -1;
//     }

//     const t1 = (-2 * (dx * vx + dy * vy) + Math.sqrt(delta)) / (2* vx * vx + 2 * vy * vy);
//     const t2 = (-2 * (dx * vx + dy * vy) - Math.sqrt(delta)) / (2* vx * vx + 2 * vy * vy);

//     if (t1 > 0 && t2 > 0) {
//       return Math.min(t1, t2);
//     } else { // 取大才可能是正数
//       return Math.max(t1, t2);
//     }
//     return -1;
//   }
// }

// export class DeskCollisionBall extends CollisionSphere {
//   constructor(name: string, r: number, x: number, y: number, vx: number, vy: number) {
//     super(CollisioObjectType.DeskBall, name, r, x, y, vx, vy);
//   }
// }

// export class DeskCollisionHole extends CollisionSphere {
//   constructor(name: string, r: number, x: number, y: number) {
//     super(CollisioObjectType.DeskHole, name, r, x, y, 0, 0);
//   }
// }

// export class DeskEdgeLine extends CollisioObject {
//   public from: Point = new Point(0, 0);
//   public to: Point = new Point(0, 0);
//   constructor(name: string, fx: number, fy: number, tx: number, ty: number) {
//     super(CollisioObjectType.DeskEdge, name);
//     this.from = new Point(fx, fy);
//     this.to = new Point(tx, ty);
//   }
//   // 计算个球 和 边，碰撞的时间
//   public sphereCollision(ball: CollisionSphere) {
//     const a = this.from.y - this.to.y;
//     const b = this.to.x - this.from.x;
//     const c = this.from.x * this.to.y - this.to.x * this.from.y;
//     const d = ball.radius * Math.sqrt(a * a + b * b);

//     const tt = a * ball.velocity.x + b * ball.velocity.y;
//     if (Math.abs(tt) < 0.0001) return -1;
//     // 绝对值里面 > 0 和 < 0 分别求一个
//     const t1 = (d - a * ball.position.x - b * ball.position.y - c) / tt;
//     const t2 = (-d - a * ball.position.x - b * ball.position.y - c) / tt;

//     // 可能两个值都是，取最小的值
//     if (t1 > 0 && t2 > 0) {
//       return Math.min(t1, t2);
//     } else { // 取大才可能是正数
//       return Math.max(t1, t2);
//     }
//     return -1;
//   }
// }

// // 桌球游戏碰撞系统
// export class DeskGameCollision {
//   public factor: number = 0.1; // 摩擦因子
//   public deltTmestamp: number = 0.02; // 每帧的间隔时间 单位秒
//   public preIndexa = -1;
//   public preIndexb = -1;
//   public static deskCollisionHoles = [
//     new DeskCollisionHole('hole1', 0.25, -18.7, 9.095),
//     new DeskCollisionHole('hole2', 0.25, 0, 9.52),
//     new DeskCollisionHole('hole3', 0.25, 18.7, 9.095),

//     new DeskCollisionHole('hole4', 0.25, 18.7, -9.095),
//     new DeskCollisionHole('hole5', 0.25, 0, -9.52),
//     new DeskCollisionHole('hole6', 0.25, -18.7, -9.095),
//   ];
//   public static deskEdgeLines = [
//     // 前横线
//     new DeskEdgeLine('edge1', -17.765, 9.52, -16.83, 8.755),
//     new DeskEdgeLine('edge2', -16.83, 8.755, -1.445, 8.755),
//     new DeskEdgeLine('edge3', -1.445, 8.755, -0.85, 9.435),
//     new DeskEdgeLine('edge4', 0.85, 9.435, 1.445, 8.755),
//     new DeskEdgeLine('edge5', 1.445, 8.755, 16.83, 8.755),
//     new DeskEdgeLine('edge6', 16.83, 8.755, 17.765, 9.62),
//     // 右竖线线
//     new DeskEdgeLine('edge7', 18.87, 8.075, 18.19, 7.225),
//     new DeskEdgeLine('edge8', 18.19, 7.225, 18.19, -7.225),
//     new DeskEdgeLine('edge9', 18.19, -7.225, 18.87, -8.075),

//     // 后横线
//     new DeskEdgeLine('edge10', 17.765, -9.62, 16.83, -8.755),
//     new DeskEdgeLine('edge11', 16.83, -8.755, 1.445, -8.755),
//     new DeskEdgeLine('edge12', 1.445, -8.755, 0.85, -9.435),
//     new DeskEdgeLine('edge13', -0.85, -9.435, -1.445, -8.755),
//     new DeskEdgeLine('edge14', -1.445, -8.755, -16.83, -8.755),
//     new DeskEdgeLine('edge15', -16.83, -8.755, -17.765, -9.52),

//     // 左竖直线
//     new DeskEdgeLine('edge16', -18.87, -8.075, -18.19, -7.225),
//     new DeskEdgeLine('edge17', -18.19, -7.225, -18.19, 7.225),
//     new DeskEdgeLine('edge18', -18.19, 7.225, -18.87, -8.075),
//   ];
//   public static instance = new DeskGameCollision(0.1, 0.02);
//   public static nextFrame(balls: Array<DeskCollisionBall>) {
//     return DeskGameCollision.instance.nextTimePosition(
//       balls, DeskGameCollision.deskEdgeLines, DeskGameCollision.deskCollisionHoles
//     );
//   }
//   constructor(factor: number, dt: number) {
//     this.factor = factor;
//     this.deltTmestamp = dt;
//   }
//   // 下一帧时，所有球的速度和位置信息
//   public nextTimePosition(
//     balls: Array<DeskCollisionBall>, edgeLines: Array<DeskEdgeLine>,
//     holes: Array<DeskCollisionHole>
//   ) {
//     const {cotType, colIndex, minTime, minIndex} = this.nearCollisionInfo(balls, edgeLines, holes);
//     console.log('next col ball ', cotType, colIndex, minTime, minIndex);
//     const retBalls = this.nextCollisionBalls(balls, edgeLines, holes, cotType, colIndex, minTime, minIndex);
//     return retBalls;
//   }
//   // 正常往下走的位置和速度
//   private moveNextPosition(ball: CollisionSphere, dt: number) {
//     const px = ball.position.x + ball.velocity.x * dt;
//     const py = ball.position.y + ball.velocity.y * dt;

//     const vx = ball.velocity.x / (1 + dt);
//     const vy = ball.velocity.y / (1 + dt);
//     const cs = new CollisionSphere(
//       ball.type, ball.name, ball.radius,
//       px, py, vx, vy
//     );

//     return cs;
//   }
//   // 两个球互相碰撞之后的位置 和 速度
//   private ballCollisionNextPosition(balla: CollisionSphere, ballb: CollisionSphere, dt: number) {
//     const csa = new CollisionSphere(
//       balla.type, balla.name, balla.radius,
//       balla.position.x + dt * balla.velocity.x, balla.position.y + dt * balla.velocity.y,
//       balla.velocity.x, balla.velocity.y
//     );

//     const csb = new CollisionSphere(
//       ballb.type, ballb.name, ballb.radius,
//       ballb.position.x + dt * ballb.velocity.x, ballb.position.y + dt * ballb.velocity.y,
//       ballb.velocity.x, ballb.velocity.y
//     );

//     const oo = balla.position.minus(ballb.position).normed();
//     const bav = this.decomposeVector(balla.velocity.asVector(), oo);
//     const bbv = this.decomposeVector(ballb.velocity.asVector(), oo);
//     // console.log('xxxx v ', bav, bbv, oo, csa, csb, balla, ballb);
//     // 沿oo方向需要交换速度
//     csa.velocity.x = bbv.a.x + bav.b.x;
//     csa.velocity.y = bbv.a.y + bav.b.y;

//     csb.velocity.x = bav.a.x + bbv.b.x;
//     csb.velocity.y = bav.a.y + bbv.b.y;

//     return {csa, csb};
//   }
//   // 和边碰撞之后的位置和速度
//   private edgeCollisionNextPosition(ball: CollisionSphere, edge: DeskEdgeLine, dt: number) {
//     const vh = edge.from.minus(edge.to).normed();
//     const vv = new Vector(vh.y, -vh.x, 1);
//     const velo = ball.velocity.asVector();
//     const vlen = velo.norm2();
//     const alpha = velo.dot(vh);
//     if (alpha < 0) {
//       vh.x = -vh.x; vh.y = -vh.y;
//     }

//     const etha = velo.dot(vv);
//     if (etha < 0) {
//       vv.x = -vv.x; vv.y = -vv.y;
//     }

//     const vhlen = velo.dot(vh) / vh.norm2();
//     vh.x = vh.x * vhlen; vh.y = vh.y * vhlen;
    
//     const vvlen = velo.dot(vv) / vv.norm2();
//     vv.x = vv.x * vvlen; vv.y = vv.y * vvlen;

//     // 垂直与边线的向量 反向
//     vv.x = -vv.x; vv.y = -vv.y;

//     const vx = (vv.x + vh.x) / (1 + dt);
//     const vy = (vv.y + vv.y) / (1 + dt);

//     const px = ball.position.x + ball.velocity.x * dt + vx * dt * 0.05;
//     const py = ball.position.y + ball.velocity.y * dt + vy * dt * 0.05;

//     const cs = new CollisionSphere(
//       ball.type, ball.name, ball.radius,
//       px, py, vx, vy
//     );

//     return cs;
//   }
//   // 速度分解 沿dira方向 和 dira 的垂直方向
//   private decomposeVector(velo: Vector, dira: Vector) {
//     const alpha = velo.dot(dira);
//     var dirv = new Vector(dira.x, dira.y);
//     if (alpha < 0) {
//       dirv.x = -dirv.x; dirv.y = -dirv.y;
//     }

//     var dirh = new Vector(-dira.y, dira.x);
//     const tha = velo.dot(dirh);
//     if (tha < 0) {
//       dirh.x = -dirh.x; dirh.y = -dirh.y;
//     }

//     return {
//       a: dirv.scale(velo.dot(dirv)),
//       b: dirh.scale(velo.dot(dirh)),
//     }
//   }
//   // 模拟下一帧球的位置和速度
//   private nextCollisionBalls(balls: Array<DeskCollisionBall>,
//     edgeLines: Array<DeskEdgeLine>, holes: Array<DeskCollisionHole>,
//     cotType: CollisioObjectType, colIndex: number, minTime: number, minIndex: number) {
//     const dt = minTime;
//     var retBalls : Array<DeskCollisionBall> = [];
//     // 没有碰撞，正常往下走一步
//     if (cotType === CollisioObjectType.Unknown) {
//       for (var i=0; i<balls.length; i++) {
//         const cs = this.moveNextPosition(balls[i], dt);
//         retBalls.push(cs);
//       }
//     } else if (cotType === CollisioObjectType.DeskBall) {
//       for (var i=0; i<balls.length; i++) {
//         if (i !== minIndex && i !== colIndex) {
//           const cs = this.moveNextPosition(balls[i], dt);
//           retBalls[i] = cs;
//         } else if (i === minIndex) {
//           const res = this.ballCollisionNextPosition(balls[i], balls[colIndex], dt);
//           retBalls[i] = res.csa;
//           retBalls[colIndex] = res.csb;
//         }
//       }
//     } else if (cotType === CollisioObjectType.DeskEdge) {
//       for (var i=0; i<balls.length; i++) {
//         var cs = this.moveNextPosition(balls[i], dt);
//         if (i === minIndex) {
//           cs = this.edgeCollisionNextPosition(balls[i], edgeLines[colIndex], dt);
//         }
//         retBalls.push(cs);
//       }
//     } else if (cotType === CollisioObjectType.DeskHole) {
//       for (var i=0; i<balls.length; i++) {
//         var cs = this.moveNextPosition(balls[i], dt);
//         if (i === minIndex) {
//           cs = this.edgeCollisionNextPosition(balls[i], edgeLines[colIndex], dt);
//         }
//         retBalls.push(cs);
//       }
//     }
//     return retBalls;
//   }
//   // 最近的一次碰撞时间
//   private nearCollisionInfo(balls: Array<DeskCollisionBall>,
//     edgeLines: Array<DeskEdgeLine>, holes: Array<DeskCollisionHole>) {
//     var minTime = this.deltTmestamp;
//     var minIndex = 0;
//     var cotType = CollisioObjectType.Unknown;
//     var colIndex = 0;
//     // 计算最近的一次碰撞最小值
//     for (var i=0; i<balls.length; i++) {
//       // ball 和 谁最先碰撞，碰撞的时间
//       for (var j=i+1; j<balls.length; j++) {
//         const t = balls[j].sphereCollision(balls[i]);
//         if (t > 0 && t < minTime) {
//           minTime = t;
//           cotType = CollisioObjectType.DeskBall;
//           minIndex = i;
//           colIndex = j;
//         }
//       }
//       // ball 和 边界碰撞
//       for (var j=0; j<edgeLines.length; j++) {
//         const t = edgeLines[j].sphereCollision(balls[i]);
//         if (t > 0 && t < minTime) {
//           minTime = t;
//           cotType = CollisioObjectType.DeskEdge;
//           minIndex = i;
//           colIndex = j;
//         }
//       }
//       // ball 和 球洞碰撞
//       for (var j=0; j<holes.length; j++) {
//         const t = holes[j].sphereCollision(balls[i]);
//         if (t > 0 && t < minTime) {
//           minTime = t;
//           cotType = CollisioObjectType.DeskHole;
//           minIndex = i;
//           colIndex = j;
//         }
//       }
//     }
//     return {
//       cotType, colIndex, minTime, minIndex,
//     }
//   }
// }
